#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int dumpMemory(int pid, uint64_t begin, uint64_t end, const char *outPath) {
  char bufMaps[256] = "/proc/self/maps";
  char bufMemPath[256] = "/proc/self/mem";

  if (pid && getuid() != 0) {
    printf(logprefix "Dump_Fix ~ " 
        "warning, program run in user:%d, please run this program by root!!!\n",
        getuid());
  }

  printf(logprefix "Dump_Fix ~ " "try dump %d from %016llx to %016llx\n", pid,
         (unsigned long long)begin, (unsigned long long)end);

  if (pid != 0) {
    sprintf(bufMaps, "/proc/%d/maps", pid);
    sprintf(bufMemPath, "/proc/%d/mem", pid);
  }

  int fMem = open(bufMemPath, O_RDONLY);
  if (!fMem) {
    // open mem error, maybe permition deny.
    printf(logprefix "Dump_Fix ~ " "open %s error, reason %s\n", bufMemPath, strerror(errno));
    return -1;
  }

  int sz = (int)(end - begin);
  unsigned char *mem = (unsigned char *)malloc(sz);
  if (!mem) {
    close(fMem);
    return -2;
  }
  memset(mem, 0, sz);

  off64_t r = lseek64(fMem, begin, SEEK_SET);
  if (r < 0) {
    printf(logprefix "Dump_Fix ~ " "fseek error return %d\n", (int)r);
  }
  printf(logprefix "Dump_Fix ~ " "try to read %s fp:%d, off=%016llx, sz=%d\n", bufMemPath, fMem,
         (unsigned long long)begin, sz);
  ssize_t szRead = read(fMem, mem, sz);
  if (szRead < 0) {
    const char *reason = strerror(errno);
    printf(logprefix "Dump_Fix ~ " "read error return %d lasterr=[%s]", (int)szRead, reason);
    return -1;
  }

  printf(logprefix "Dump_Fix ~ " "read return %d\n", (int)szRead);

  size_t left = sz - szRead;
  if (left > 0) {
    printf(logprefix "Dump_Fix ~ " "dump %d left\n", (unsigned)left);
    for (size_t i = 0; i < left; ++i) {
      unsigned char byte = 0;
      ssize_t szB = read(fMem, &byte, 1);
      if (szB < 1) {
        lseek64(fMem, 1, SEEK_CUR);
        continue;
      }
      mem[szRead + i] = byte;
    }
  }
  int fOut = open(outPath, O_WRONLY | O_CREAT, 0666);
  if (fOut < 0) {
    printf(logprefix "Dump_Fix ~ " "open %s error:%s\n", outPath, strerror(errno));
  }
  ssize_t szW = write(fOut, mem, sz);
  printf(logprefix "Dump_Fix ~ " "%d writed\n", (unsigned)szW);
  close(fOut);

  free(mem);
  close(fMem);
  return 0;
}
